package jocl.samples;

import org.jocl.*;

import static org.jocl.CL.*;
import static org.jocl.CL.CL_MEM_READ_WRITE;
import static org.jocl.CL.clCreateBuffer;

/**
 * Created with IntelliJ IDEA.
 * User: Duy Chung
 * Date: 9/15/13
 * Time: 10:21 PM
 * To change this template use File | Settings | File Templates.
 */
public class Computation extends Thread {

    private int globalSize;
    private cl_kernel kernel;
    private cl_command_queue command;
    private cl_device_id device;
    private cl_context context;
    private int size;
    float input[];
    private cl_mem inputMem;
    private cl_mem outputMem;
    cl_program program;
    cl_event events[];
    boolean done = false;
    float output[];
    int index;

    public Computation(int size,
                       int index,
                       cl_context context,
                       cl_program program,
                       cl_device_id device) {
        this.device = device;
        this.size = size;
        this.index = index;
        this.context = context;
        this.program = program;
        input = new float[size];
        output = new float[size/3];
        init();

    }

    private void init() {
        kernel = clCreateKernel(program, "sampleKernel", null);
        inputMem = clCreateBuffer(context,
                                          CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                                          Sizeof.cl_float * size,
                                          Pointer.to(input), null);

        outputMem = clCreateBuffer(context,
                                      CL_MEM_READ_WRITE,
                                      Sizeof.cl_float * size,
                                      null, null);
        long properties = 0;
        properties |= CL.CL_QUEUE_PROFILING_ENABLE;
        command = clCreateCommandQueue(context, device, properties, null);
        events = new cl_event[1];
        clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(inputMem));
        clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(outputMem));
        clSetKernelArg(kernel, 2, Sizeof.cl_int, Pointer.to(new int[]{size}));

        events[0] = new cl_event();

    }


    // run thread here
    public void run() {
//        init();

        long before = System.nanoTime();
//        System.out.println("Enqueueing kernels");
//        System.out.print("Thread: " + getName() + " running");
        clEnqueueNDRangeKernel(command,
                kernel,
                1,
                null,
                new long[]{size/3}, // global work size
                null,
                0,
                null,
                events[0]);


        clWaitForEvents(events.length, events);
        long after = System.nanoTime();
        float totalDurationMs = (after-before)/1e6f;
        System.out.println("Total duration of " + getName() + ": " +totalDurationMs+"ms");
//        clEnqueueReadBuffer(command, outputMem, CL_TRUE, 0,
//                    size/3 * Sizeof.cl_float, Pointer.to(output), 0, null, null);


        releaseResources();

        done = true;
        System.out.println("Thread " + getName() + "IS DONE!!");

    }

    // release resource
    public void releaseResources() {
        clReleaseKernel(kernel);
        clReleaseProgram(program);
        clReleaseMemObject(inputMem);
        clReleaseMemObject(outputMem);
        clReleaseEvent(events[0]);
        clReleaseCommandQueue(command);
        clReleaseContext(context);
    }

    public boolean isDone() {
        return done;
    }
}
